package com.admin.server.dao;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.admin.server.acl.My_Acl;
import com.admin.server.acl.My_Acl_Role;
import com.admin.server.config.PMF;
import com.admin.server.domain.Menu;
import com.admin.server.domain.MenuRol;
import com.admin.server.domain.MenuUsuario;
import com.admin.server.domain.Rol;
import com.admin.server.domain.Usuario;
import com.admin.share.model.MenuDTO;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class Menus {

public static Integer errorTipo = 0;
	
	public static String usuario_id;
	public static Integer tipo;
	private static My_Acl acl;
	
	public static Long getPrivilegioUsuario(String user_id) {		
		Key ckey = KeyFactory.stringToKey(user_id);		
		return ckey.getParent().getId();
	}

	public static List<MenuDTO> getTreeMenuAdmin() {
		List<MenuDTO> menus = new ArrayList<MenuDTO>();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try{						
			Menu e = getMenuRoot(pm);
			for (Menu m : e.getChildren()) {
				MenuDTO mDTO = m.toDTO();
				menus.add(mDTO);
				if(mDTO.getHaschildren()){
					getMenuHijoAdmin(m, mDTO);
				}            	
            }
		}finally{
			pm.close();
		}
		return menus;
	}

	private static void getMenuHijoAdmin(Menu m, MenuDTO mDTO) {
		for (Menu mnu : m.getChildren()) {
			MenuDTO menuDTO = mnu.toDTO();
			mDTO.add(menuDTO);
			if(menuDTO.getHaschildren()){
				getMenuHijoAdmin(mnu, menuDTO);
			}
        }
	}

	public static List<MenuDTO> getTreeMenuPermitidos() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		acl = new My_Acl();
		List<MenuDTO> menus = new ArrayList<MenuDTO>();
		
		addResources();
    	
		acl.user_id = usuario_id;
    	acl.parents_id = getRoles(usuario_id);
    	
    	acl.beforeAllow();
    	addPermisosRoles();
    	
    	try{
    		Menu e = getMenuRoot(pm);
    		for (Menu m : e.getChildren()) {					
				MenuDTO mDTO = m.toDTO();
				mDTO.setPermitido(usuarioHas(pm, m.getKey()));					
				menus.add(mDTO);
			}
    		
    		String resource_id;
    		for (Iterator<MenuDTO> iter = menus.iterator(); iter.hasNext();) {
    			MenuDTO mnu = iter.next();
    			if(mnu.getPermitido()==null){
    				resource_id = mnu.getId();
    				
    				if(acl.isAllowed(resource_id)){
    					if(mnu.getHaschildren() != null){				
    						getMenuHijoPermitido(mnu);
    					}
    				}					
    				else{
    					iter.remove();					
    				}
    								
    			}else if(mnu.getPermitido()){
    				if(mnu.getHaschildren() != null){				
    					getMenuHijoPermitido(mnu);
    				}				
    			}else{
    				iter.remove();
    			}
    				      
    	    }
    	}finally{
    		pm.close();
    	}
		return menus;
	}

	private static void getMenuHijoPermitido(MenuDTO menu) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<MenuDTO> menus = new ArrayList<MenuDTO>();
		try{
			Key menu_key = KeyFactory.stringToKey(menu.getId());
			Menu e = pm.getObjectById(Menu.class, menu_key);
			for (Menu m : e.getChildren()) {					
				MenuDTO mDTO = m.toDTO();
				mDTO.setPermitido(usuarioHas(pm, m.getKey()));					
				menus.add(mDTO);
			}
			
			String resource_id;
			for (MenuDTO mnu : menus) {
				if(mnu.getPermitido()==null){
					resource_id = mnu.getId();
					
					if(acl.isAllowed(resource_id)){
						if(mnu.getTipo()==1)
							menu.add(mnu);
						else if(mnu.getTipo()==2){
							if(menu.permisos == null){
								menu.permisos = new ArrayList<String>();
							}
							menu.permisos.add(mnu.getParametro());
							menu.setHaschildren(null);
						}
					}
					
					if(mnu.getHaschildren() != null)
						getMenuHijoPermitido(mnu);
										
				}else if(mnu.getPermitido()){
					if(mnu.getTipo()==1)
						menu.add(mnu);
					else if(mnu.getTipo()==2){
						if(menu.permisos == null){
							menu.permisos = new ArrayList<String>();
						}
						menu.permisos.add(mnu.getParametro());
						menu.setHaschildren(null);
					}
					
					if(mnu.getHaschildren() != null)
						getMenuHijoPermitido(mnu);					
				}
			}
		}finally{
			pm.close();
		}
		
	}

	public static List<MenuDTO> getTreeMenu() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		acl = new My_Acl();
		List<MenuDTO> menus = new ArrayList<MenuDTO>();
		try{
			if(tipo!= null){
	        	addResources();
	        	if (tipo == 1){
	        		addRolPadre(usuario_id);
	        		acl.beforeAllow();
	        		addPermisosRoles();
	        	}else if(tipo == 2){
	        		acl.user_id = usuario_id;
	            	acl.parents_id = getRoles(usuario_id);
	            	
	            	acl.beforeAllow();
	            	addPermisosRoles();
	        	}        	
	        }
			Menu e = getMenuRoot(pm);
			if(tipo == null){				
				for (Menu m : e.getChildren()) {
					MenuDTO mDTO = m.toDTO();
					menus.add(mDTO);
				}
			}else if(tipo == 1){//tipo 1 es un rol			
				for (Menu m : e.getChildren()) {					
					MenuDTO mDTO = m.toDTO();
					mDTO.setPermitido(rolHas(pm, m.getKey()));					
					menus.add(mDTO);
				}
			}else if(tipo == 2){//tipo 2 indica es un usuario			
				for (Menu m : e.getChildren()) {					
					MenuDTO mDTO = m.toDTO();
					mDTO.setPermitido(usuarioHas(pm, m.getKey()));					
					menus.add(mDTO);
				}
			}
			
			String resource_id;
			for (MenuDTO mnu : menus) {				
				if(tipo!= null)
				if(mnu.getPermitido()==null){
					resource_id = mnu.getId();
					if(tipo == 1){
						if(acl.isAllowed(usuario_id, resource_id))
							mnu.setPermitido(true);
					}else if(tipo==2){
						if(acl.isAllowed(resource_id))
							mnu.setPermitido(true);
					}				
				}
				if(mnu.getHaschildren() != null){				
					getMenuHijo(mnu);
				}
		    }
		}finally{
			pm.close();
		}
		return menus;
	}

	private static void getMenuHijo(MenuDTO menu) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<MenuDTO> menus = new ArrayList<MenuDTO>();
		try{
			Key menu_key = KeyFactory.stringToKey(menu.getId());
			Menu e = pm.getObjectById(Menu.class, menu_key);
			if(tipo == null){				
				for (Menu m : e.getChildren()) {
					MenuDTO mDTO = m.toDTO();
					menus.add(mDTO);
				}
			}else if(tipo == 1){//tipo 1 es un rol			
				for (Menu m : e.getChildren()) {					
					MenuDTO mDTO = m.toDTO();
					mDTO.setPermitido(rolHas(pm, m.getKey()));					
					menus.add(mDTO);
				}
			}else if(tipo == 2){//tipo 2 indica es un usuario			
				for (Menu m : e.getChildren()) {					
					MenuDTO mDTO = m.toDTO();
					mDTO.setPermitido(usuarioHas(pm, m.getKey()));					
					menus.add(mDTO);
				}
			}
			String resource_id;
			for (MenuDTO mnu : menus) {
				if(tipo!= null)
					if(mnu.getPermitido()==null){
						resource_id = mnu.getId();
						if(tipo == 1){
							if(acl.isAllowed(usuario_id, resource_id))
								mnu.setPermitido(true);
						}else if(tipo==2){
							if(acl.isAllowed(resource_id))
								mnu.setPermitido(true);
						}					
					}
					menu.add(mnu);
					
					if(mnu.getHaschildren() != null)
						getMenuHijo(mnu);
			}
			
		}finally{
			pm.close();
		}
		
	}

	@SuppressWarnings("unchecked")
	private static void addPermisosRoles() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<String> roles_id = acl.getAllRoles();
		try{
			for(String rol_id: roles_id){
				Key rol_key = KeyFactory.stringToKey(rol_id);
				Query q = pm.newQuery("select menu_key from "+MenuRol.class.getName()+" where rol_key == :rol_k && permitido == true");
				List<Key> permitidos = (List<Key>)q.execute(rol_key);
				for(Key item : permitidos){
					String menu_id = KeyFactory.keyToString(item);
					acl.allow(rol_id, menu_id);
				}
				
				q = pm.newQuery("select menu_key from "+MenuRol.class.getName()+" where rol_key == :rol_k && permitido == false");
				List<Key> nopermitidos = (List<Key>)q.execute(rol_key);
				for(Key item : nopermitidos){
					String menu_id = KeyFactory.keyToString(item);
					acl.deny(rol_id, menu_id);
				}
			}
		}finally{
			pm.close();
		}
		
	}

	private static List<String> getRoles(String usuario_id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key usuario_key = KeyFactory.stringToKey(usuario_id);
		List<String> roles_id = new ArrayList<String>();
		try{
			Usuario user = pm.getObjectById(Usuario.class, usuario_key);
			Set<Key> rol_keys = user.getRol_ids();
			for(Key rol_key : rol_keys){
				String rol_id = KeyFactory.keyToString(rol_key);
				roles_id.add(rol_id);
				if(rol_key.getId() != 7){//root
					String parent_id = KeyFactory.keyToString(rol_key.getParent());
					acl.addRole(new My_Acl_Role(rol_id, parent_id));
					addRolPadre(parent_id);
				}else
					acl.addRole(new My_Acl_Role(rol_id));
			}
		}finally{
			pm.close();
		}
		return roles_id;
	}

	private static void addRolPadre(String rol_id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key rol_key = KeyFactory.stringToKey(rol_id);
		try{
		Rol rol = pm.getObjectById(Rol.class, rol_key);
		if(rol_key.getId() != 7){//root
			String parent_id = KeyFactory.keyToString(rol.getParent().getKey());
			acl.addRole(new My_Acl_Role(rol_id, parent_id));
			addRolPadre(parent_id);
		}else{
			acl.addRole(new My_Acl_Role(rol_id));
		}
		
		}finally{
			pm.close();
		}
		
	}

	@SuppressWarnings("unchecked")
	private static void addResources() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		List<Key> keys = null;		
		try{
			Query q = pm.newQuery("select key from "+Menu.class.getName());
			keys = (List<Key>)q.execute();
			
			for(Key item:keys){
				acl.add(KeyFactory.keyToString(item));
			}
		}finally{
			pm.close();
		}
	}
	
	private static Menu getMenuRoot(PersistenceManager pm){		
		Key k = KeyFactory.createKey(Menu.class.getSimpleName(), 4);//root			
		Menu e = pm.getObjectById(Menu.class, k);		
		return e;
	}
	
	private static Boolean rolHas(PersistenceManager pm, Key menu_key){
		String rol_id = usuario_id;
		Key rol_key = KeyFactory.stringToKey(rol_id);
		Query q = pm.newQuery("select permitido from "+MenuRol.class.getName()+" where menu_key == :mk && rol_key == :rk");
		q.setUnique(true);		
		return (Boolean)q.execute(menu_key, rol_key);
	}
	
	private static Boolean usuarioHas(PersistenceManager pm, Key menu_key){		
		Key usuario_key = KeyFactory.stringToKey(usuario_id);
		Query q = pm.newQuery("select permitido from "+MenuUsuario.class.getName()+" where menu_key == :mk && usuario_key == :uk");
		q.setUnique(true);		
		return (Boolean)q.execute(menu_key, usuario_key);
	}
}
